package com.appbee.cm.client.nav.presenter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;

import com.appbee.cm.shared.data.NavItemProxy;
import com.appbee.core.client.event.EntityChange;
import com.appbee.core.client.place.INamePlace;
import com.appbee.core.client.util.PathIndex;
import com.google.gwt.event.shared.EventBus;
import com.google.web.bindery.requestfactory.shared.WriteOperation;

@Singleton
public class NavControl
{
	PathIndex<NavItemWrap> pathIndex = new PathIndex<NavItemWrap>();
	HashMap<Long, NavItemWrap> index = new HashMap<Long, NavItemWrap>();
	private List<NavItemWrap> navItems;
	private List<NavItemWrap> firstLevelItems;
	private final EventBus eventBus;
	private final NavDataProvider dataProvider;
	private final Provider<NavDataProvider> dataProviderProvider;

	@Inject
	public NavControl(	EventBus eventBus,
						Provider<NavDataProvider> dataProviderProvider)
	{
		this.eventBus = eventBus;
		this.dataProviderProvider = dataProviderProvider;
		this.dataProvider = dataProviderProvider.get();
	}

	public NavItemWrap getByPlace(INamePlace namePlace)
	{
		String name = namePlace.getName();
		return pathIndex.get(name);
	}

	public NavControl add(NavItemProxy navItem)
	{
		NavItemWrap wrap = new NavItemWrap(navItem);
		pathIndex.add(navItem.getPath(), wrap);
		index.put(navItem.getId(), wrap);
		hockUpTree(wrap);
		navItems.add(wrap);
		if (wrap.getParent() == null)
			firstLevelItems.add(wrap);
		eventBus.fireEventFromSource(new EntityChange<NavItemProxy>(navItem,
				WriteOperation.PERSIST), NavItemProxy.class);
		return this;
	}

	private void hockUpTree(NavItemWrap wrap)
	{
		long parentId = wrap.getWrappedItem().getParentId();
		if (parentId != 0)
		{
			NavItemWrap parent = index.get(parentId);
			wrap.setParent(parent);
			if (parent.getChildren().isEmpty())
				parent.setNavDataProvider(dataProviderProvider.get());
			parent.getChildren().add(wrap);
		}
	}

	public void setNavItems(List<NavItemProxy> navProxyItems)
	{
		this.navItems = new ArrayList<NavItemWrap>();
		this.firstLevelItems = new ArrayList<NavItemWrap>();
		for (NavItemProxy navItem : navProxyItems)
		{
			NavItemWrap itemWrap = new NavItemWrap(navItem);
			pathIndex.add(	navItem.getPath() == null ? "" : navItem.getPath(),
							itemWrap);
			index.put(navItem.getId(), itemWrap);
			navItems.add(itemWrap);
		}

		// Hock up tree
		for (NavItemWrap navItem : navItems)
		{
			hockUpTree(navItem);
			if (navItem.getParent() == null)
				firstLevelItems.add(navItem);
		}
		dataProvider.setData(firstLevelItems);
	}

	public List<NavItemWrap> getNavItems()
	{
		return navItems;
	}

	public List<NavItemWrap> getFirstLevelItems()
	{
		return firstLevelItems;
	}

	public NavItemWrap getById(Long navId)
	{
		return index.get(navId);
	}

	public List<NavItemWrap> getChildrenByParentId(	Long parentId,
													String displayType)
	{
		List<NavItemWrap> list;
		if (parentId == null)
		{
			list = getFirstLevelItems();
		}
		else
		{
			NavItemWrap itemWrap = index.get(parentId);
			list = itemWrap == null ? new ArrayList<NavItemWrap>() : itemWrap
					.getChildren();
		}
		List<NavItemWrap> returnList = new ArrayList<NavItemWrap>();
		for (NavItemWrap navItemWrap : list)
		{
			if (navItemWrap.getWrappedItem().getDisplayType() == null
					|| navItemWrap.getWrappedItem().getDisplayType()
					.equals(displayType))
			{
				returnList.add(navItemWrap);
			}
		}
		return returnList;
	}

	public NavDataProvider getDataProvider()
	{
		return dataProvider;
	}

	public void remove(NavItemWrap navItem)
	{
		if (navItem.getNavDataProvider() != null)
			navItem.getNavDataProvider().removeHandler();

		pathIndex.remove(navItem.getPath());
		index.remove(navItem.getWrappedItem().getId());
		navItems.remove(navItem);
		if (navItem.getParent() != null)
		{
			navItem.getParent().getChildren().remove(navItem);
			if (navItem.getParent().getChildren().isEmpty())
				navItem.getParent().getNavDataProvider().removeHandler();
		}
		else
		{
			firstLevelItems.remove(navItem);
		}
		eventBus.fireEventFromSource(	new EntityChange<NavItemProxy>(
navItem
												.getWrappedItem(),
												WriteOperation.DELETE),
										NavItemProxy.class);

	}

}
